/*
	SoundCapToRes -- a HyperCard user-defined command to create a 
	'snd ' resource from a SoundCap file.
	©Apple Computer, Inc. 1987
	All Rights Reserved.

	To compile and link this file using Macintosh Programmer's Workshop,

	C -q2 -g -ga SoundCapToRes.c
	link -sn Main=SoundCapToRes -sn STDIO=SoundCapToRes ¶
		-sn INTENV=SoundCapToRes -rt XCMD=20 ¶
		-m SOUNDCAPTORES SoundCapToRes.c.o ¶
		"{CLibraries}"StdCLib.o  "{CLibraries}"CInterface.o ¶
		-o SoundCapMover
	
	This link directive puts the XCMD in the stack "SoundCapMover".
	Substitute the name of the stack you want it in.  To move XCMDs
	between stacks, use ResEdit.  They can be in an individual stack,
	the Home stack, the HyperCard application, or the System File.
	Don't use SndCapToRes to install a sound in the current stack or 
	the Home stack (they're already open and in use).
	
	(XCMD=0 for flash from Pascal, =5 for cFlash from C)
	(XCMD=11 Panasonic, =12 Hitachi, =13 Phillips, =14 PioneerLDV6000,
	=15 PioneerLVP4200, =20 SoundCapToRes)
*/


/*
 * Usage: Type a command into a Hypertalk script. (SoundCapToRes must be
 *		installed as a XCMD using ResEdit, see above). 
 *
 *	SoundCapToRes ResName,SndFile,StackFile,BaseNote
 *	SoundCapToRes "Flute","Flute.cap",Sounds,60
 *
 *  By Steve Milne and Ted Kaehler.  DO NOT call the authors!
 *  Contact Apple Developer Support on AppleLink "MacDts"
 *  or on MCI "MacTech".
 *
 */

#include <Types.h>
#include <StdIO.h>
#include <Resources.h>
#include <Memory.h>
#include <OSUtils.h>
#include <SM.h>
#include <HyperXCmd.h>


typedef struct SoundRes {
	short				format;
	short				refct;
	short				numCommands;
	SndCommand			command1;	/* add more lines like this for 
									more commands */
	SoundHeader			header;
	char				data[0];	
} SoundRes;

pascal	void	Debugger()	extern 0xA9FF;

	
pascal void SoundCapToRes(paramPtr)
	XCmdBlockPtr	paramPtr;
{
	char *	ResName;
	char *	SourceFileName;
	char *	DestFileName;
	short	resRefNum;
	short	baseNote;
	Handle	theData,
			ConstructRes ();
	short	resID;
	short	refNum;
	long	ticks;
	Str255	str;
	
	
	if (paramPtr->paramCount < 3) return; /* baseNote is optional */
	ResName = *(paramPtr->params[0]);
	SourceFileName = *(paramPtr->params[1]);
	DestFileName = *(paramPtr->params[2]);
	if (paramPtr->paramCount >= 4)
	{
		/* 4th param is baseNote.  Convert it to a pascal string */
		ZeroToPas(paramPtr,*(paramPtr->params[3]),&str);
		/* Convert the string to a number */
		baseNote = StrToNum(paramPtr,&str);
	}
	else
	{
		baseNote = 60;  /* default is middle C, natural pitch */
	}

	
	/* Open the sound file. */
	if (FSOpen(SourceFileName,0,&refNum) != noErr)
	{
		/* Cannot open soundCap input file */
		SysBeep(10);
		Delay(3, &ticks);
		SysBeep(10);
		/* return an error message */
		return;
	}
	
	
	/* Open the resource file.  If it doesn't exist, create it and
	 * open it.  */
	if ( (resRefNum = OpenResFile (DestFileName)) == -1 )
	{
		CreateResFile (DestFileName);
		if ( ResError() != noErr )
		{
			/* Cannot create resource file: */
			return;
		}
		else if (resRefNum = OpenResFile (DestFileName) == -1 )
		{
			/* Cannot open created resource file (change iths later to replace) */
			return;
		}
	}
	
	
	/*   Check the baseNote	*/
	if ( (baseNote < 1) || (baseNote > 120) )
	{
		/* baseNote is out of range */
		return;
	}

	
	/*
	 * See if the resource ID is unique.  If not create it.
	 * remove the old resource, if any 
	 */
	
	resID = GetNameAndID (resRefNum, ResName);
	
	/*
	 * Construct the resource.
	 */
	if ( (theData = ConstructRes (refNum, baseNote, resID)) != nil )
		AddRes (theData, resID, ResName);
		
	/*
	 * Close the sound file and resource file.
	 */
	FSClose (refNum);
	CloseResFile (resRefNum);
	
	/*
	 * Dispose of the handle.
	 */
	if ( theData ) DisposHandle (theData);

	return;
}

	

/* GetNameAndID
 * See if the resource name is already in use.  If it is, delete it
 * and we will create a new one in AddRes.  Get a new random
 * resource ID if no resource of that name existed.
 */
	
GetNameAndID (resRefNum, resName)
short	resRefNum;
char	* resName;
{
	short	resID;
	Handle	dummy;
	ResType	snd_Type;
	Boolean	foundName;
	
	snd_Type = 'snd ';
	SetResLoad (false);	/* prevent the resource from being loaded */
	dummy = GetNamedResource(snd_Type, resName);	/* look for it by name */
	foundName = (dummy != nil);		/* its there already */
	/* make sure its in exactly the file, not up the chain */
	if (foundName) foundName = ( HomeResFile(dummy) == resRefNum );
	if (foundName)
	{
		/* get rid of the existing resource with the same name */
		GetResInfo(dummy, &resID, &snd_Type, resName);	/* set resID */
		RmveResource(dummy);
	}
	else
	{	
		/* assign a new random ID */
		resID = UniqueID(snd_Type);
	}
	SetResLoad (true);	/* allow loading again */
	return resID;
}


/*
 * Construct the resource and write it out to the resource file.
 */
Handle
ConstructRes (refNum, baseNote, resID)
short	refNum;
short	baseNote;
short	resID;
{
	long		length;
	SoundRes	*sndResPtr;
	Handle		theData;
	char		*pointer;
	Boolean		NoSynth;

	/*
	 * Figure out how long the source file is.  This is the number of
	 * samples of sound.
	 */
	
	if  (GetEOF(refNum, &length) != noErr) 
	{
		/* can't read end of file */
		return nil;
	}

	/*
	 * Allocate a handle for the resource.
	 */
	if ( (theData = NewHandle ( sizeof (SoundRes) + length )) == nil )
	{
		/* Not enough memory */
		return nil;
	}
	HLock(theData);
	
	/*
	 * Fill in the resource information.
	 */
	/* Format 2 'snd ' resurces assume that the application is using the
	sampled synthesizer (snth=5).  Space is provided for the application
	to do reference counting on the resource.  sndCapToRes does not put
	any notes in (by itself, this sound installs an instrument but is 
	silent.  The Play command in HyperTalk will supply the notes. */
	
	sndResPtr = *theData;
	
	sndResPtr->format 				= 2;	/* Format 2 */
	sndResPtr->refct		 		= 0;	/* space for reference count */
	sndResPtr->numCommands 			= 1;

	sndResPtr->command1.commandNum	= SoundCmd + DataPointerFlag;
	sndResPtr->command1.wordArg	= 0;
	sndResPtr->command1.longArg		= sizeof (SoundRes) - sizeof (SoundHeader);
	
	sndResPtr->header.samplePtr		= 0;
	sndResPtr->header.length		= length;
	sndResPtr->header.sampleRate	= 0x56EE8BA4;	/* sampling rate 22Khz */
	sndResPtr->header.loopStart		= length - 2;
	sndResPtr->header.loopEnd		= length - 1;
	sndResPtr->header.baseNote		= baseNote;
	
	/*
	 * Copy the data from the source file to the end of the resource.
	 */
	pointer = sndResPtr->data;
	FSRead(refNum, &length, pointer);
	
	HUnlock(theData);
	
	return theData;
}

/*
 * Add and write out a resource.
 */

AddRes (theData, resID, resName)
	Handle	theData;
	short	resID;
	char	*resName;
{
	ResType	snd_Type;

	/*
	 * Add the resource to the file and write it out.
	 */
	snd_Type = 'snd ';
	AddResource (theData, snd_Type, resID, resName);
	if ( ResError() != noErr )
	{
		/* Cannot add the resource. */
		return -1;
	}
	
	/*  Make the 'snd ' resource purgable  */
	SetResAttrs(theData,(GetResAttrs(theData) | 0x20));
	
	WriteResource (theData);
	if ( ResError() != noErr )
	{
		/* Cannot write the resource. */
		return -1;
	}
	
	return 0;
}

/* C routines for HyperCard callbacks */
#include <XCmdGlue.inc.c>
